/*
 * Copyright 2007 Rob Nielsen
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * 	http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.googlecode.proxymatic.core.util;

import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;

public final class ReflectUtil {
    public static boolean isStatic(Method method) {
        return (method.getModifiers() & Modifier.STATIC) > 0;
    }

    public static boolean isAbstract(Class classToCheck) {
        return (classToCheck.getModifiers() & Modifier.ABSTRACT) > 0;
    }

    public static Method getMethod(Class parentClass, String methodName) {
        return getMethod(parentClass, methodName, new Class[]{});
    }

    public static Method getMethod(Class parentClass, String methodName, Class parameterType) {
        return getMethod(parentClass, methodName, new Class[]{parameterType});
    }

    public static Method getMethod(Class parentClass, String methodName, Class... parameterTypes) {
        try {
            return parentClass.getMethod(methodName, parameterTypes);
        } catch (NoSuchMethodException e) {
            throw new RuntimeException(e);
        }
    }

    public static Method[] getMethodsWithName(Class parentClass, String methodName) {
        List<Method> list = new ArrayList<Method>();
        Method[] methods = parentClass.getMethods();
        for (int i = 0; i < methods.length; i++) {
            Method method = methods[i];
            if (method.getName().equals(methodName)) {
                list.add(method);
            }
        }
        return list.toArray(new Method[list.size()]);
    }

    public static Class[] createClassArray(Object[] implementationObjects) {
        Class[] classes = new Class[implementationObjects.length];
        for (int i = 0; i < classes.length; i++) {
            classes[i] = implementationObjects[i].getClass();
        }
        return classes;
    }

    public static Class[] createInterfaceArray(Object[] implementationObjects) {
        return createInterfaceArray(implementationObjects, new Class[0]);
    }

    public static Class[] createInterfaceArray(Object[] implementationObjects, Class[] extraInterfaces) {
        Set<Class> set = new LinkedHashSet<Class>();
        for (int i = 0; i < extraInterfaces.length; i++) {
            set.add(extraInterfaces[i]);
        }
        for (int i = 0; i < implementationObjects.length; i++) {
            Object implementationObject = implementationObjects[i];
            Class[] classes = implementationObject.getClass().getInterfaces();
            set.addAll(Arrays.asList(classes));
        }
        return set.toArray(new Class[0]);
    }

    public static boolean isInstanceOrBoxed(Class classToCheck, Object instance) {
        if (classToCheck.isPrimitive()) {
            classToCheck = PrimitiveUtil.getBoxedClass(classToCheck);
        }
        return classToCheck.isInstance(instance);
    }
}
